home *** CD-ROM | disk | FTP | other *** search
/ Ham Radio 2000 #2 / Ham Radio 2000 - Volume 2.iso / HAMV2 / TCP_IP / TNOS230S / BOOTP.C < prev    next >
Encoding:
C/C++ Source or Header  |  1997-01-19  |  9.4 KB  |  375 lines

  1. /*
  2.  * Center for Information Technology Integration
  3.  *           The University of Michigan
  4.  *                    Ann Arbor
  5.  *
  6.  * Dedicated to the public domain.
  7.  * Send questions to info@citi.umich.edu
  8.  *
  9.  * BOOTP is documented in RFC 951 and RFC 1048
  10.  * Delinted, ANSIfied and reformatted - 5/30/91 P. Karn
  11.  */
  12.  
  13.  
  14. #include "global.h"
  15. #ifdef BOOTPCLIENT
  16. #include "commands.h"
  17. #ifndef MSDOS
  18. #include <time.h>
  19. #endif
  20. #include "mbuf.h"
  21. #include "netuser.h"
  22. #include "udp.h"
  23. #include "domain.h"
  24. #include "bootp.h"
  25.  
  26. #if !defined(_lint)
  27. static char rcsid[] OPTIONAL = "$Id: bootp.c,v 1.17 1997/01/19 21:13:05 root Exp root $";
  28. #endif
  29.  
  30. static int bootp_rx (struct iface *ifp, struct mbuf *bp);
  31. static void ntoh_bootp (struct mbuf **bpp, struct bootp *bootpp);
  32.  
  33. #if 0
  34. static int mask2width (int32 mask);
  35. #endif
  36.  
  37. #define BOOTP_TIMEOUT    30    /* Time limit for booting       */
  38. #define BOOTP_RETRANS    5    /* The inteval between sendings */
  39.  
  40. #ifdef    BOOTP
  41. int WantBootp = 0;
  42. #endif
  43.  
  44. static int SilentStartup = 0;
  45.  
  46.  
  47.  
  48. int
  49. dobootp (int argc, char **argv, void *p OPTIONAL)
  50. {
  51. struct iface *ifp = NULLIF;
  52. struct socket lsock, fsock;
  53. struct mbuf *bp;
  54. struct udp_cb *bootp_cb;
  55. register unsigned char *cp;
  56. time_t now,        /* The current time (seconds)   */
  57.        starttime,    /* The start time of sending BOOTP */
  58.        lastsendtime;    /* The last time of sending BOOTP  */
  59. int i;
  60.  
  61.     if (argc < 2)        /* default to the first interface */
  62.         ifp = Ifaces;
  63.     else {
  64.         for (i = 1; i != argc; ++i) {
  65.  
  66.             if ((ifp = if_lookup (argv[i])) != NULLIF)
  67.                 continue;
  68.             else if (strncmp (argv[i], "silent", strlen (argv[i])) == 0)
  69.                 SilentStartup = 1;
  70.             else if (strncmp (argv[i], "noisy", strlen (argv[i])) == 0)
  71.                 SilentStartup = 0;
  72.             else {
  73.                 tputs ("bootp [net_name] [silent] [noisy]\n");
  74.                 return 1;
  75.             }
  76.         }
  77.     }
  78.  
  79.     if (ifp == NULLIF)
  80.         return 0;
  81.  
  82.     lsock.address = ifp->addr;
  83.     lsock.port = IPPORT_BOOTPC;
  84.  
  85.     if ((bootp_cb = open_udp (&lsock, NULLVFP ((struct iface *, struct udp_cb *, int16)))) == NULLUDP)
  86.         return 0;
  87.  
  88.     fsock.address = ifp->broadcast;
  89.     fsock.port = IPPORT_BOOTPS;
  90.  
  91.     /* Get boot starting time */
  92.     (void) time (&starttime);
  93.     lastsendtime = 0;
  94.  
  95.     /* Send the bootp request packet until a response is received or time
  96.        out */
  97.     for ( ; ; ) {
  98.  
  99.         /* Allow bootp packets should be passed through iproute. */
  100.         WantBootp = 1;
  101.  
  102.         /* Get the current time */
  103.         (void) time (&now);
  104.  
  105.         /* Stop, if time out */
  106.         if (now - starttime >= BOOTP_TIMEOUT) {
  107.             tputs ("bootp: timed out, values not set\n");
  108.             break;
  109.         }
  110.         /* Don't flood the network, send in intervals */
  111.         if (now - lastsendtime > BOOTP_RETRANS) {
  112.             if (!SilentStartup)
  113.                 tputs ("Requesting...\n");
  114.  
  115.             /* Allocate BOOTP packet and fill it in */
  116.             if ((bp = alloc_mbuf (sizeof (struct bootp))) == NULLBUF)
  117.                       break;
  118.  
  119.             cp = bp->data;    /* names per the RFC: */
  120.             *cp++ = BOOTREQUEST;            /* op */
  121.             *cp++ = uchar(ifp->iftype->type);    /* htype */
  122.             *cp++ = uchar(ifp->iftype->hwalen);    /* hlen */
  123.             *cp++ = 0;                /* hops */
  124.             cp = put32 (cp, (uint32) now);        /* xid */
  125.             cp = put16 (cp, (int16)(now - starttime)); /* secs */
  126.             cp = put16 (cp, 0);            /* unused */
  127.             cp = put32 (cp, ifp->addr);        /* ciaddr */
  128.             cp = put32 (cp, 0L);            /* yiaddr */
  129.             cp = put32 (cp, 0L);            /* siaddr */
  130.             cp = put32 (cp, 0L);            /* giaddr */
  131.             memcpy (cp, ifp->hwaddr, (size_t) ifp->iftype->hwalen);
  132.             cp += 16;                /* chaddr */
  133.             memset (cp, 0, 64);            /* sname */
  134.             cp += 64;
  135.             memset (cp, 0, 128);            /* file */
  136.             cp += 128;
  137.             memset (cp, 0, 64);            /* vend */
  138.             cp += 64;
  139.             bp->cnt = (int16)(cp - bp->data);
  140.             /* assert(bp->cnt == BOOTP_LEN) */
  141.  
  142.             /* Send out one BOOTP Request packet as a broadcast */
  143.             (void) send_udp (&lsock, &fsock, 0, 0, bp, bp->cnt, 0, 0);
  144.  
  145.             lastsendtime = now;
  146.         }
  147.         /* Give other tasks a chance to run. */
  148.         kwait (NULL);
  149.  
  150.         /* Test for and process any replies */
  151.         if (recv_udp (bootp_cb, &fsock, &bp) > -1) {
  152.             if (bootp_rx (ifp, bp))
  153.                 break;
  154.         } else if (Net_error != WOULDBLK) {
  155.             tprintf ("bootp: Net_error %d, no values set\n", Net_error);
  156.             break;
  157.         }
  158.     }
  159.  
  160.     WantBootp = 0;
  161.     (void) del_udp (bootp_cb);
  162.     return 0;
  163. }
  164.  
  165.  
  166.  
  167. /* Process BOOTP input received from 'interface'. */
  168. static int
  169. bootp_rx (struct iface *ifp, struct mbuf *bp)
  170. {
  171. int ch;
  172. int count;
  173. uint32 gateway = 0;
  174. uint32 nameserver = 0;
  175. uint32 broadcast, netmask;
  176. struct route *rp;
  177. struct bootp reply;
  178. unsigned char *cp;
  179.  
  180.     if (len_p (bp) != sizeof (struct bootp)) {
  181.         free_p (bp);
  182.         return 0;
  183.     }
  184.     ntoh_bootp (&bp, &reply);
  185.     free_p (bp);
  186.  
  187.     if (reply.op != BOOTREPLY)
  188.         return 0;
  189.  
  190.     if (!SilentStartup)
  191.         tprintf ("Network %s configured:\n", ifp->name);
  192.  
  193.     if (ifp->addr == 0) {
  194.         Ip_addr = reply.yiaddr.s_addr;        /* yiaddr */
  195.         ifp->addr = reply.yiaddr.s_addr;    /* yiaddr */
  196.         if (!SilentStartup)
  197.             tprintf ("     IP address: %s\n", inet_ntoa (ifp->addr));
  198.     }
  199.     /* now process the vendor-specific block, check for cookie first. */
  200.     cp = (unsigned char *) reply.vend;
  201.     if (get32 (reply.vend) != 0x63825363L) {
  202.         tcmdprintf ("bootp: Invalid magic cookie.\n");
  203.         return (0);
  204.     }
  205.     cp += 4;
  206.     while (((ch = *cp) != BOOTP_END) && (++cp < (unsigned char *) (reply.vend + 64)))
  207.         switch (ch) {
  208.             case BOOTP_PAD:    /* They're just padding */
  209.                 continue;
  210.             case BOOTP_SUBNET:    /* fixed length, 4 octets */
  211.                 cp++;    /* moved past length */
  212.  
  213.                 /* Set the netmask */
  214.                 /* Remove old entry if it exists */
  215.                 netmask = get32 ((char *) cp);
  216.                 cp += 4;    /*lint !e662 */
  217.  
  218.                 rp = rt_blookup (ifp->addr & ifp->netmask, (unsigned) mask2width (ifp->netmask));
  219.                 if (rp != NULLROUTE)
  220.                     (void) rt_drop (rp->target, rp->bits);
  221.                 ifp->netmask = netmask;
  222.                 (void) rt_add (ifp->addr, (unsigned) mask2width (ifp->netmask), 0L, ifp, 0L, 0L, 0);
  223.  
  224.                 if (!SilentStartup)
  225.                     tprintf ("     Subnet mask: %s\n", inet_ntoa (netmask));
  226.  
  227.                 /* Set the broadcast */
  228.                 broadcast = ifp->addr | ~(ifp->netmask);
  229.                 rp = rt_blookup (ifp->broadcast, 32);
  230.                 if (rp != NULLROUTE && rp->iface == ifp)
  231.                     (void) rt_drop (ifp->broadcast, 32);
  232.                 ifp->broadcast = broadcast;
  233.                 (void) rt_add (ifp->broadcast, 32, 0L, ifp, 1L, 0L, 1);
  234.  
  235.                 if (!SilentStartup)
  236.                     tprintf ("     Broadcast: %s\n", inet_ntoa (broadcast));
  237.  
  238.                 break;
  239.             case BOOTP_HOSTNAME:
  240.                 count = (int) *cp;
  241.                 cp++;
  242.  
  243.                 if (Hostname != NULLCHAR)
  244.                     free (Hostname);
  245.                 Hostname = mallocw ((unsigned) count);
  246.                 strncpy (Hostname, (char *) cp, (size_t) count);
  247.                 cp += count;
  248.  
  249.                 if (!SilentStartup)
  250.                     tprintf ("     Hostname: %s\n", Hostname);
  251.                 break;
  252.             case BOOTP_DNS:
  253.                 count = (int) *cp;
  254.                 cp++;
  255.  
  256.                 while (count) {
  257.                     nameserver = get32 ((char *) cp);
  258.                     (void) add_nameserver (nameserver, 0);
  259.                     if (!SilentStartup)
  260.                         tprintf ("     Nameserver: %s\n", inet_ntoa (nameserver));
  261.                     cp += 4;    /*lint !e662 */
  262.                     count -= 4;
  263.                 }
  264.                 break;
  265.             case BOOTP_GATEWAY:
  266.                 count = (int) *cp;
  267.                 cp++;
  268.  
  269.                 gateway = get32 ((char *) cp);
  270.  
  271.                 /* Add the gateway as the default */
  272.                 (void) rt_add (0, 0, gateway, ifp, 1, 0, 0);
  273.  
  274.                 if (!SilentStartup)
  275.                     tprintf ("     Default gateway: %s\n", inet_ntoa (gateway));
  276.                 cp += count;
  277.                 break;
  278.             default:    /* variable field we don't know about */
  279.                 count = (int) *cp;
  280.                 cp++;
  281.  
  282.                 cp += count;
  283.                 break;
  284.         }
  285.  
  286.     (void) rt_add (ifp->addr, (unsigned) mask2width (ifp->netmask), 0L, ifp, 1, 0, 0);    /*lint !e661 !e662 */
  287.  
  288.     return (1);
  289. }
  290.  
  291.  
  292.  
  293. static void
  294. ntoh_bootp (struct mbuf **bpp, struct bootp *bootpp)
  295. {
  296.     bootpp->op = (char) pullchar (bpp);        /* op */
  297.     bootpp->htype = (char) pullchar (bpp);        /* htype */
  298.     bootpp->hlen = (char) pullchar (bpp);        /* hlen */
  299.     bootpp->hops = (char) pullchar (bpp);        /* hops */
  300.     bootpp->xid = (long) pull32 (bpp);        /* xid */
  301.     bootpp->secs = pull16 (bpp);            /* secs */
  302.     bootpp->unused = pull16 (bpp);            /* unused */
  303.     bootpp->ciaddr.s_addr = pull32 (bpp);        /* ciaddr */
  304.     bootpp->yiaddr.s_addr = pull32 (bpp);        /* ciaddr */
  305.     bootpp->siaddr.s_addr = pull32 (bpp);        /* siaddr */
  306.     bootpp->giaddr.s_addr = pull32 (bpp);        /* giaddr */
  307.     (void) pullup (bpp, (unsigned char *) bootpp->chaddr, 16);    /* chaddr */
  308.     (void) pullup (bpp, (unsigned char *) bootpp->sname, 64);    /* sname */
  309.     (void) pullup (bpp, (unsigned char *) bootpp->file, 128);    /* file name */
  310.     (void) pullup (bpp, (unsigned char *) bootpp->vend, 64);    /* vendor */
  311. }
  312.  
  313.  
  314.  
  315. #ifdef    BOOTP
  316.  
  317. int
  318. bootp_validPacket (struct ip *ip, struct mbuf **bpp)
  319. {
  320. struct udp udp;
  321. struct pseudo_header ph;
  322. int status;
  323.  
  324.  
  325.     /* Must be a udp packet */
  326.     if (ip->protocol != UDP_PTCL)
  327.         return 0;
  328.  
  329.     /* Invalid if packet is not the right size */
  330.     if (len_p (*bpp) != (sizeof (struct udp) + sizeof (struct bootp)))
  331.         return 0;
  332.  
  333.     /* Invalid if not a udp bootp packet */
  334.     ntohudp (&udp, bpp);
  335.  
  336.     status = (udp.dest == IPPORT_BOOTPC) ? 1 : 0;
  337.  
  338.     /* Restore packet, data hasn't changed */
  339.     /* Create pseudo-header and verify checksum */
  340.     ph.source = ip->source;
  341.     ph.dest = ip->dest;
  342.     ph.protocol = ip->protocol;
  343.     ph.length = ip->length - IPLEN - ip->optlen;
  344.  
  345.     *bpp = htonudp (&udp, *bpp, &ph);
  346.  
  347.     return status;
  348. }
  349.  
  350. #endif
  351.  
  352.  
  353.  
  354. #if 0                /* no longer needed, as it is in iface.c */
  355. /* Given a network mask, return the number of contiguous 1-bits starting
  356.  * from the most significant bit.
  357.  */
  358. static int
  359. mask2width (int32 mask)
  360. {
  361. int width, i;
  362.  
  363.     width = 0;
  364.     for (i = 31; i >= 0; i--) {
  365.         if (!(mask & (1L << i)))
  366.             break;
  367.         width++;
  368.     }
  369.     return width;
  370. }
  371.  
  372. #endif
  373.  
  374. #endif    /* BOOTPCLIENT */
  375.